# -*- coding: utf-8 -*-

import sys
import re
import ppc
import ppc.task


class Flag(object):
    """
    Pipe类的状态或指令标记枚举
    """
    (Normal, Break) = range(2)


class Pipe(object):
    """
    Pipe类
    对传入的数据进行特定的处理，并传出处理后的数据。所有管道组件都应从此类继承,并重写handle方法。
    """

    def __init__(self, id, target=[]):
        self.id = id
        self.target = target

        self.input = None
        self.output = None
        
        self.flag = Flag.Normal
        self._params = {}

        self._generator = self._generate()
        next(self._generator)

    def addParameter(self, param):
        assert(isinstance(param, Parameter))
        tag = param.tag
        if tag not in self._params:
            self._params[tag] = param
        else:
            if isinstance(self._params[tag], list):
                self._params[tag].append(param)
            else:
                self._params[tag] = [self._params[tag], param]

    def send(self, data):
        self._generator.send(data)

    def transfer(self, data):
        self.output = data
        for t in self.target:
            ppc.task.Task.instance.pipes[t].send(data)

    def __getitem__(self, key):
        return self._params[key]

    def __contains__(self, key):
        return key in self._params

    def _refresh(self):
        for p in self._params.values():
            if isinstance(p, list):
                for item in p:
                    item.oval(self.id)
            else:
                p.oval(self.id)

    def _generate(self):
        while True:
            self.input = (yield)
            self._refresh()
            self.handle()

    def handle(self):
        print('{0} handler is not implemented'.format(self.id))


class Parameter(dict):
    """
    Pipe的参数类
    继承自dict，使索引可以以属性的方式访问,并且可以保留和恢复各项的初始值
    """

    def __init__(self, *args, **kwargs):
        self.tag = args[0]
        args = args[1:]
        self.__orig__ = dict(*args, **kwargs)
        super(Parameter, self).__init__(*args, **kwargs)

    def __getattr__(self, attr):
        return self[attr]

    def __setattr__(self, attr, value):
        self[attr] = value

    def oval(self, pipeid):
        for k, v in self.__orig__.items():
            self[k] = Evaluator.evaluate(v, pipeid)

    def ohas(self, key):
        return key in self.__orig__

    def oget(self, key):
        return self.__orig__[key]

    def oset(self, key, value):
        self.__orig__[key] = value


class Evaluator(object):
    """
    对变量标签根据运行时取值(一般在任务的xml配置文件中出现)
    """
    @classmethod
    def evaluate(cls, val, pipeid):
        L = []
        argsRE = re.compile(r"""(\{@(\w+)(?:\|(.*))?(\!)?\})""")
        matches = argsRE.findall(val)
        for m in matches:
            (txt, arg, default, emark) = m

            if arg.isdigit():
                arg = int(arg)
                
            replacement = ppc.CmdlineArguments.instance[arg]
            if not replacement:
                replacement = default
            elif not isinstance(replacement, str):
                replacement = str(replacement)

            val = val.replace(txt, replacement)

            if emark:
                L.append(replacement)

        inputRE = re.compile(r"""(\{\$(\w+)(\.[\w_\-]+)?(\!)?\})""")
        matches = inputRE.findall(val)
        for m in matches:
            (txt, tag, attr, emark) = m
            if tag == '_':
                tag = pipeid
            data = ppc.task.Task.instance.pipes[tag].input
            attr = attr.lstrip('.')
            if attr:
                if attr in data:
                    data = data[attr]
                elif hasattr(data, attr):
                    data = getattr(data, attr)

            if emark:
                L.append(data)

            if not isinstance(data, str):
                data = str(data)
            val = val.replace(txt, data)

        outputRE = re.compile(r"""(\{\#(\w+)(\.[\w_\-]+)?(\!)?\})""")
        matches = outputRE.findall(val)
        for m in matches:
            (txt, tag, attr, emark) = m
            if tag == '_':
                tag = pipeid
            data = ppc.task.Task.instance.pipes[tag].output
            attr = attr.lstrip('.')
            if attr:
                if attr in data:
                    data = data[attr]
                elif hasattr(data, attr):
                    data = getattr(data, attr)

            if emark:
                L.append(data)

            if not isinstance(data, str):
                data = str(data)
            val = val.replace(txt, data)

        if L:
            return L if len(L) > 1 else L[0]

        return val

